package com.ms.service.module.analysis;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.ms.service.module.analysis.async.UpdateRealTimeAnalysisModelAsync;
import com.ms.service.module.analysis.db.AnalysisDAO;
import com.ms.service.module.analysis.db.model.RealTimeAnalysisModelV2;
import com.xpec.c4.game.common.Helper;


/**
 * 即時人數統計資訊
 */
public class RealTimeAnalysisManager {
	
	private static final Log log = LogFactory.getLog(RealTimeAnalysisManager.class);

	public static final int ADD = 1;
	public static final int REMOVE = 2;
	public static final int UPDATE = 3;
	
	/**
	 * 運用的module
	 */
	private AnalysisModule opModule;
	
	/**
	 * cache起來的model
	 */
	private ArrayList<RealTimeAnalysisModelV2> modelList;
	
	/**
	 * 比較方便get的map
	 */
	private HashMap<PlatformType, HashMap<GameNameWithHallType, HashMap<BigDecimal, RealTimeAnalysisModelV2>>> modelMap = new HashMap<PlatformType, HashMap<GameNameWithHallType,HashMap<BigDecimal,RealTimeAnalysisModelV2>>>();
	
	
	/**
	 * 初始化
	 */
	public void init(AnalysisModule module){
		if(module == null){
			if(log.isErrorEnabled()){
				log.error("init fail, module is null");
			}
			return;
		}
		
		opModule = module;
		
		//把所有model從DB讀取出來
		modelList = AnalysisDAO.getRealTimeModels(true);
		
		//把所有紀錄歸零
		for(RealTimeAnalysisModelV2 model : modelList){
			//歸零
			model.setRealTimeMemberFormal(0);
			model.setRealTimeMemberTrial(0);
			model.setRealTimeMemberNoAccount(0);
			model.setRealTimeMemberOfflineSpin(0);

			model.setTotalBetFormal(BigDecimal.ZERO);
			model.setTotalBetNoAccount(BigDecimal.ZERO);
			model.setTotalBetOfflineSpin(BigDecimal.ZERO);
			model.setTotalBetTrail(BigDecimal.ZERO);
			
			model.setRealTimeBetFormal(BigDecimal.ZERO);
			model.setRealTimeBetOfflineSpin(BigDecimal.ZERO);
			model.setRealTimeBetTrial(BigDecimal.ZERO);
			model.setRealTimeBetNoAccount(BigDecimal.ZERO);
			
			//放進比較好get的map
			PlatformType platformType = model.getPlatformType();
			HashMap<GameNameWithHallType, HashMap<BigDecimal, RealTimeAnalysisModelV2>> platformMap = modelMap.get(platformType);
			if(platformMap == null){
				platformMap = new HashMap<GameNameWithHallType, HashMap<BigDecimal,RealTimeAnalysisModelV2>>();
				modelMap.put(platformType, platformMap);
			}
			
			GameNameWithHallType gameHall = model.getGameNameWithHallType();
			HashMap<BigDecimal, RealTimeAnalysisModelV2> gameHallMap = platformMap.get(gameHall);
			if(gameHallMap == null){
				gameHallMap = new HashMap<BigDecimal, RealTimeAnalysisModelV2>();
				platformMap.put(gameHall, gameHallMap);
			}
			
			BigDecimal gainRate = model.getGainRate();
			gameHallMap.put(gainRate, model);
			
		}
		
		UpdateRealTimeAnalysisModelAsync async = new UpdateRealTimeAnalysisModelAsync();
		async.addModels(modelList);
		async.setUpdateType(UpdateRealTimeAnalysisModelAsync.ALL);
		module.addAsyncCommand(async);
	}
	
	private RealTimeAnalysisModelV2 getModel(PlatformType platformType, GameNameWithHallType gameHall, BigDecimal gainRate){
		if(platformType == null || gameHall == null || gainRate == null){
			return null;
		}
		
		RealTimeAnalysisModelV2 modelForUpdate = null;
		try {
			//為了符合從model建立起的key，這裡的scale要跟model相符才行
			//目前看起來都是用到2
			BigDecimal gainRateKey = gainRate.setScale(Helper.VALUE_SCALE);
			modelForUpdate = modelMap.get(platformType).get(gameHall).get(gainRateKey);
		} catch (Exception e) {
			if (log.isErrorEnabled()) {
				log.error("get model in modelMap fail, " + platformType.name() + "/" + gameHall.name() + "/"
						+ gainRate.toString());
			}
			return null;
		}
		
		return modelForUpdate;
	}
	
	/**
	 * 從機台資訊更新
	 */
	public void updateBySeatData(int updateType, PlayerSeatData seatData) {
		if(opModule == null){
			if(log.isErrorEnabled()){
				log.error("updateBySeatData fail, module is null");
			}
			return;
		}
		
		if(modelList == null){
			if(log.isErrorEnabled()){
				log.error("updateBySeatData fail, modelList is null");
			}
			return;
		}
		
		if(seatData == null){
			if(log.isErrorEnabled()){
				log.error("updateBySeatData fail, seatData is null, updateType="+updateType);
			}
			return;
		}

		PlatformType platformType = seatData.getPlatformType();
		GameNameWithHallType gameHall = seatData.getGameNameWithHallType();
		MemberType memberType = seatData.getMemberType();
		String gainRateStr = seatData.getGainRateStr();
		BigDecimal gainRate = new BigDecimal(gainRateStr);
		BigDecimal lastBet = seatData.getLastBet();

		RealTimeAnalysisModelV2 modelForUpdate = getModel(platformType, gameHall, gainRate);
		
		if(modelForUpdate == null){
			if(log.isErrorEnabled()){
				log.error("can't get model in model map,"+ platformType.name() + "/" + gameHall.name() + "/"
						+ gainRateStr);
			}
			return;
		}
		
		int updateDBType = UpdateRealTimeAnalysisModelAsync.MEMBER;
		switch (updateType) {
		case ADD: {
			updateMemberCount(modelForUpdate, memberType, true);
			break;
		}
		case REMOVE: {
			updateMemberCount(modelForUpdate, memberType, false);
			break;
		}
		case UPDATE: {
			addTotalBet(true, modelForUpdate, memberType, lastBet);
			updateDBType = UpdateRealTimeAnalysisModelAsync.TOTAL_BET;
			break;
		}

		default:
			return;
		}

		UpdateRealTimeAnalysisModelAsync async = new UpdateRealTimeAnalysisModelAsync();
		async.addModel(modelForUpdate);
		async.setUpdateType(updateDBType);
		opModule.addAsyncCommand(async);
	}
	
	/**
	 * 更新model的人數
	 */
	private void updateMemberCount(RealTimeAnalysisModelV2 model, MemberType memberType, boolean isAdd){
		
		int change = (isAdd) ? 1 : -1;
		
		switch (memberType) {
		case FORMAL_MEMBER: {
			model.setRealTimeMemberFormal(model.getRealTimeMemberFormal() + change);
			break;
		}
		case OFFLINE_SPIN_MEMBER: {
			model.setRealTimeMemberOfflineSpin(model.getRealTimeMemberOfflineSpin() + change);
			break;
		}
		case TRAIL_MEMBER: {
			model.setRealTimeMemberTrial(model.getRealTimeMemberTrial() + change);
			break;
		}
		case NO_ACCOUNT: {
			model.setRealTimeMemberNoAccount(model.getRealTimeMemberNoAccount() + change);
			break;
		}

		default:
			return;
		}
		
	}
	
	/**
	 * 累積下注
	 */
	private void addTotalBet
	(
			boolean isTotalBet,
			RealTimeAnalysisModelV2 model,
			MemberType memberType,
			BigDecimal lastBet
	)
	{
		if(Helper.isMinus(lastBet)){
			return;
		}
		
		switch (memberType) {
		case FORMAL_MEMBER: {
			if(isTotalBet){
				model.setTotalBetFormal(Helper.add(model.getTotalBetFormal(), lastBet));	
			}
			else{
				model.setRealTimeBetFormal(Helper.add(model.getRealTimeBetFormal(), lastBet));
			}
			
			break;
		}
		case OFFLINE_SPIN_MEMBER: {
			if(isTotalBet){
				model.setTotalBetOfflineSpin(Helper.add(model.getTotalBetOfflineSpin(), lastBet));	
			}
			else{
				model.setRealTimeBetOfflineSpin(Helper.add(model.getRealTimeBetOfflineSpin(), lastBet));
			}
			
			break;
		}
		case TRAIL_MEMBER: {
			if(isTotalBet){
				model.setTotalBetTrail(Helper.add(model.getTotalBetTrail(), lastBet));	
			}
			else{
				model.setRealTimeBetTrial(Helper.add(model.getRealTimeBetTrial(), lastBet));
			}
			
			break;
		}
		case NO_ACCOUNT: {
			if(isTotalBet){
				model.setTotalBetNoAccount(Helper.add(model.getTotalBetNoAccount(), lastBet));	
			}
			else{
				model.setRealTimeBetNoAccount(Helper.add(model.getRealTimeBetNoAccount(), lastBet));
			}
			
			break;
		}

		default:
			return;
		}
		
	}
	
	/**
	 * 將資訊更新到即時下住
	 */
	public void updateRealTimeBet(HashMap<String, PlayerSeatData> seatDatas){
		if(opModule == null){
			if(log.isErrorEnabled()){
				log.error("updateRealTimeBet fail, module is null");
			}
			return;
		}
		
		if(seatDatas == null){
			return;
		}
		
		for(RealTimeAnalysisModelV2 model : modelList){
			//歸零即時下注
			model.setRealTimeBetFormal(BigDecimal.ZERO);
			model.setRealTimeBetOfflineSpin(BigDecimal.ZERO);
			model.setRealTimeBetTrial(BigDecimal.ZERO);
			model.setRealTimeBetNoAccount(BigDecimal.ZERO);
		}
		
		//對所有座位的資訊來更新
		for(PlayerSeatData data : seatDatas.values()){
			if(data.isLastBetEffective()){
				PlatformType platformType = data.getPlatformType();
				GameNameWithHallType gameHall = data.getGameNameWithHallType();
				BigDecimal gainRate = new BigDecimal(data.getGainRateStr());
				RealTimeAnalysisModelV2 model = getModel(platformType, gameHall, gainRate);
				
				MemberType memberType = data.getMemberType();
				addTotalBet(false, model, memberType, data.getLastBet());
			}
		}
		
		//更新到DB
		UpdateRealTimeAnalysisModelAsync async = new UpdateRealTimeAnalysisModelAsync();
		async.addModels(modelList);
		async.setUpdateType(UpdateRealTimeAnalysisModelAsync.REAL_TIME_BET);
		opModule.addAsyncCommand(async);
	}
	
}

